package httpserver

import (
	"context"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/julienschmidt/httprouter"
	"mime/multipart"
	"net/http"
	"net/url"
	"sync"
)

type Ctx struct {
	httpContext context.Context
	writer      http.ResponseWriter
	request     *http.Request

	routerParams httprouter.Params

	IHttpResponse

	//支持gin框架
	ginContext *gin.Context
}

var ctxPool sync.Pool

func init() {
	ctxPool.New = func() interface{} {
		return &Ctx{}
	}
}

func NewCtx(writer http.ResponseWriter, request *http.Request) *Ctx {
	//todo 待支持pool
	//ctx := ctxPool.Get().(*Ctx)
	ctx := &Ctx{}
	if writer != nil && request != nil {
		ctx.Reset(writer, request)
	}

	return ctx
}

func destroyCtx(ctx *Ctx) {
	ctxPool.Put(ctx)
}

func (ctx *Ctx) Reset(writer http.ResponseWriter, request *http.Request) {
	ctx.writer = writer
	ctx.request = request
	ctx.httpContext = request.Context()
	ctx.IHttpResponse = NewHttpResponse(writer)
}

func (ctx *Ctx) Gin() *gin.Context {
	return ctx.ginContext
}

func (ctx *Ctx) setGin(c *gin.Context) {
	ctx.ginContext = c
}

func (ctx *Ctx) _setRouterParams(params httprouter.Params) {
	ctx.routerParams = params
}

func (ctx *Ctx) Context() context.Context {
	return ctx.httpContext
}

func (ctx *Ctx) WithValue(key, val interface{}) {
	ctx.httpContext = context.WithValue(ctx.httpContext, key, val)
}

func (ctx *Ctx) Form() url.Values {
	r := ctx.request

	form := url.Values{}
	r.ParseForm()
	form = r.Form

	return form
}

func (ctx *Ctx) FormJson(stc interface{}) error {
	r := ctx.request
	contentType := r.Header.Get("Content-Type")

	switch contentType {
	case "application/json":
		if r.Body == nil {
			return nil
		}
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&stc)
		if err != nil {
			return err
		}
	default:
	}

	return nil
}

func (ctx *Ctx) FormMultipart() (map[string][]string, map[string][]*multipart.FileHeader, error) {
	r := ctx.request
	err := r.ParseMultipartForm(128)
	if err != nil {
		return nil, nil, err
	}

	return r.MultipartForm.Value, r.MultipartForm.File, nil
}

func (ctx *Ctx) Value(key interface{}) interface{} {
	return ctx.httpContext.Value(key)
}

func (ctx *Ctx) SetResponseHandler(response IHttpResponse) {
	ctx.IHttpResponse = response
}

func (ctx *Ctx) Writer() http.ResponseWriter {
	return ctx.writer
}

func (ctx *Ctx) Request() *http.Request {
	return ctx.request
}

func (ctx *Ctx) Param(name string) string {
	return ctx.routerParams.ByName(name)
}

func (ctx *Ctx) SetParam(kv ...string) {
	for i := 1; i < len(kv); i += 2 {
		ctx.routerParams = append(ctx.routerParams, httprouter.Param{
			Key:   kv[i-1],
			Value: kv[i],
		})
	}
}

func (ctx *Ctx) WriteHeader(code int) {
	ctx.writer.WriteHeader(code)
}

func (ctx *Ctx) Header() http.Header {
	return ctx.writer.Header()
}

func (ctx *Ctx) Write(resp []byte) (int, error) {
	return ctx.writer.Write(resp)
}

func (ctx *Ctx) WriteStr(resp string) (int, error) {
	return ctx.writer.Write([]byte(resp))
}

func (ctx *Ctx) Authorization() string {
	return ctx.request.Header.Get("Authorization")
}
